#include <iostream>
#include "../../ArbolB+/ArbolBMas.h"
#include "../../Archivos/Configuracion.h"

#include <../lib/igloo/igloo.h>

using namespace std;
using namespace igloo;
using namespace Arboles;
Context(arbolBMasTest)
{

	ArbolBMas* arbol;
	string path;
	Configuracion* config;

	void SetUp() {
		config = Configuracion::getInstancia("archivoConfiguracionTestArbol.txt");
		arbol = new ArbolBMas("TestAlta");
	}

	void TearDown() {
		string path = config->getPathArbol() + "arbol" + "TestAlta" + ".bin";
		remove(path.c_str());
		string pathNodosLibres = config->getPathArbol() + "nodosLibres" + "TestAlta" + ".bin";
		remove(pathNodosLibres.c_str());
		delete config;
		delete arbol;
	}

	Spec(insertarArbol) {

		arbol->insertar("241011Caba", 99);
		NodoHoja* raiz = new NodoHoja(0, 0, 100);
		raiz->setNumeroNodo(0);
		arbol->getNodo(raiz);
		string claveNodoInsertado = raiz->getRegistros()->at(0)->getClave();

		Assert::That(claveNodoInsertado, Is().EqualTo("241011Caba"));
		Assert::That(raiz->getRegistros()->at(0)->getOffsets()->at(0), Is().EqualTo(99));

		delete raiz;
	}

	Spec(sobreFlujoRaiz) {

		arbol->insertar("241011Caba", 34); // 22 caracteres agregamos (+12 de metadata)
		arbol->insertar("241011Rosa", 56);
		arbol->insertar("241011Cord", 78);
		arbol->insertar("241011Salt", 100);
		arbol->insertar("241011Tasa", 122);
		arbol->insertar("241011Trel", 144);
		arbol->insertar("241011Zumu", 166);

		NodoInterno* raiz = new NodoInterno(0, 50);
		raiz->setNumeroNodo(0);
		arbol->getNodo(raiz);

		NodoHoja* hijoIzquierdo = new NodoHoja(0, 0, 400);
		hijoIzquierdo->setNumeroNodo(2);
		arbol->getNodo(hijoIzquierdo);

		NodoHoja* hijoDerecho = new NodoHoja(0, 0, 400);
		hijoDerecho->setNumeroNodo(1);
		arbol->getNodo(hijoDerecho);

		Assert::That(raiz->getNivel(), Is().EqualTo(1));
		Assert::That(raiz->getRegistros()->at(0)->getClave(), Is().EqualTo("241011Tasa"));
		Assert::That(raiz->getRegistros()->size(), Is().EqualTo(1));

		Assert::That(hijoIzquierdo->getReferenciaNodoSiguiente(), Is().EqualTo(1));
		Assert::That(hijoIzquierdo->getNumeroNodo(), Is().EqualTo(2));
		Assert::That(hijoIzquierdo->getRegistros()->size(), Is().EqualTo(4));

		Assert::That(hijoDerecho->getReferenciaNodoSiguiente(), Is().EqualTo(0));
		Assert::That(hijoDerecho->getNumeroNodo(), Is().EqualTo(1));
		Assert::That(hijoDerecho->getRegistros()->size(), Is().EqualTo(3));

		delete raiz;
		delete hijoIzquierdo;
		delete hijoDerecho;
	}

	Spec(sobreflujoRaizLuegoSobreflujoHoja) {

		arbol->insertar("241011Caba", 34); // 22 caracteres agregamos (+12 de metadata)
		arbol->insertar("241011Rosa", 56);
		arbol->insertar("241011Cord", 78);
		arbol->insertar("241011Salt", 100);
		arbol->insertar("241011Tasa", 122);
		arbol->insertar("241011Trel", 144);
		arbol->insertar("241011Zumu", 166);

		/* hasta acá tenemos:
		 * Nodo raiz: 2 | 241011Tasa | 1
		 *		  2: 241011Caba,34 | 241011Cord,78 | 241011Rosa,56 | 241011Salt,100 (100 bytes en el nodo)
		 *		  1: 241011Tasa,122 | 241011Trel,144 | 241011Zumu,166               (78 bytes en el nodo)
		 *
		 * Insertamos 3 registros más para sobrecargar el nodo 2 (hijo izquierdo)
		 */


		arbol->insertar("241011Avel", 122);
		arbol->insertar("241011Barr", 144);
		arbol->insertar("241011Caab", 166);

		NodoInterno* raiz = new NodoInterno(0, 50);
		raiz->setNumeroNodo(0);
		arbol->getNodo(raiz);

		NodoHoja* hijoIzquierdo = new NodoHoja(0, 0, 400);
		hijoIzquierdo->setNumeroNodo(2);
		arbol->getNodo(hijoIzquierdo);

		NodoHoja* hijoDelMedio = new NodoHoja(0, 0, 400);
		hijoDelMedio->setNumeroNodo(3);
		arbol->getNodo(hijoDelMedio);

		NodoHoja* hijoDerecho = new NodoHoja(0, 0, 400);
		hijoDerecho->setNumeroNodo(1);
		arbol->getNodo(hijoDerecho);

		Assert::That(raiz->getNivel(), Is().EqualTo(1));
		Assert::That(raiz->getRegistros()->size(), Is().EqualTo(2));

		Assert::That(raiz->getRegistros()->at(0)->getReferenciaNodoIzquierdo(), Is().EqualTo(2));
		Assert::That(raiz->getRegistros()->at(0)->getClave(), Is().EqualTo("241011Cord"));
		Assert::That(raiz->getRegistros()->at(0)->getReferenciaNodoDerecho(), Is().EqualTo(3));
		Assert::That(raiz->getRegistros()->at(1)->getReferenciaNodoIzquierdo(), Is().EqualTo(3));
		Assert::That(raiz->getRegistros()->at(1)->getClave(), Is().EqualTo("241011Tasa"));
		Assert::That(raiz->getRegistros()->at(1)->getReferenciaNodoDerecho(), Is().EqualTo(1));

		Assert::That(hijoIzquierdo->getReferenciaNodoSiguiente(), Is().EqualTo(3));
		Assert::That(hijoIzquierdo->getNivel(), Is().EqualTo(0));
		Assert::That(hijoIzquierdo->getRegistros()->size(), Is().EqualTo(4));

		Assert::That(hijoDerecho->getReferenciaNodoSiguiente(), Is().EqualTo(0));
		Assert::That(hijoDerecho->getNivel(), Is().EqualTo(0));
		Assert::That(hijoDerecho->getRegistros()->size(), Is().EqualTo(3));

		delete raiz;
		delete hijoIzquierdo;
		delete hijoDelMedio;
		delete hijoDerecho;
	}

	Spec(modificarArbolTest){

		arbol->insertar("241011Caba", 34); // 22 caracteres agregamos (+12 de metadata)
		arbol->insertar("241011Rosa", 56);
		arbol->insertar("241011Cord", 78);
		arbol->insertar("241011Salt", 100);
		arbol->insertar("241011Tasa", 122);
		arbol->insertar("241011Trel", 144);
		arbol->insertar("241011Zumu", 166);

		arbol->insertar("241011Avel", 122);
		arbol->insertar("241011Barr", 144);
		arbol->insertar("241011Caab", 166);
		//exploto nodo 2
		arbol->insertar("241011Cabb", 122);
		arbol->insertar("241011Bara", 144);
		arbol->insertar("241011Cara", 166);
		//exploto nodo 3
		arbol->insertar("241011Ropa", 122);
		arbol->insertar("241011Sang", 144);
		arbol->insertar("241011Mara", 166);
		arbol->insertar("241011Marx", 166);

		//exploto nodo 1
		arbol->insertar("241011Vota", 122);
		arbol->insertar("241011Wilo", 144);
		arbol->insertar("241011Urug", 166);
		arbol->insertar("241011Vale", 166);

		//exploto nodo 1 otra vez
		arbol->insertar("241011Vali", 144);
		arbol->insertar("241011Valu", 166);
		arbol->insertar("241011Valo", 166);

		string claveABuscar = "241011Cord";
		unsigned int offsetEsperado = 300;

		arbol->modificar(claveABuscar,78,300);

		NodoHoja* nodoHoja = new NodoHoja(0,0,160);
		nodoHoja->setNumeroNodo(3);
		arbol->getNodo(nodoHoja);

		unsigned int offsetNuevo = nodoHoja->getRegistros()->at(0)->getOffsets()->at(0);

		Assert::That(offsetEsperado, Is().EqualTo(offsetNuevo));

		delete nodoHoja;
	}

	Spec(siguienteArbolTest){

		arbol->insertar("241011Caba", 34); // 22 caracteres agregamos (+12 de metadata)
		arbol->insertar("241011Rosa", 56);
		arbol->insertar("241011Cord", 78);
		arbol->insertar("241011Salt", 100);
		arbol->insertar("241011Tasa", 122);
		arbol->insertar("241011Trel", 144);
		arbol->insertar("241011Zumu", 166);

		arbol->insertar("241011Avel", 122);
		arbol->insertar("241011Barr", 144);
		arbol->insertar("241011Caab", 166);
		//exploto nodo 2
		arbol->insertar("241011Cabb", 122);
		arbol->insertar("241011Bara", 144);
		arbol->insertar("241011Cara", 166);
		//exploto nodo 3
		arbol->insertar("241011Ropa", 122);
		arbol->insertar("241011Sang", 144);
		arbol->insertar("241011Mara", 166);
		arbol->insertar("241011Marx", 166);

		//exploto nodo 1
		arbol->insertar("241011Vota", 122);
		arbol->insertar("241011Wilo", 144);
		arbol->insertar("241011Urug", 166);
		arbol->insertar("241011Vale", 166);

		//exploto nodo 1 otra vez
		arbol->insertar("241011Vali", 144);
		arbol->insertar("241011Valu", 166);
		arbol->insertar("241011Valo", 166);

		//Entro primer hoja
		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();
		//Salgo primer hoja

		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();

		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();

		//rama derecha
		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();

		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();

		arbol->siguiente();
		arbol->siguiente();
		arbol->siguiente();

		arbol->siguiente();
		arbol->siguiente();

		string claveProximoRegistroEsperado = "241011Zumu";

		RegistroArbol* proximoRegistroRespuesta = arbol->siguiente();

		Assert::That(claveProximoRegistroEsperado, Is().EqualTo(proximoRegistroRespuesta->getClave()));
	}

	Spec(buscarArbolTest_devuelveRegistroConMismaClave){

			arbol->insertar("241011Caba", 34); // 22 caracteres agregamos (+12 de metadata)
			arbol->insertar("241011Rosa", 56);
			arbol->insertar("241011Cord", 78);
			arbol->insertar("241011Salt", 100);
			arbol->insertar("241011Tasa", 122);
			arbol->insertar("241011Trel", 144);
			arbol->insertar("241011Zumu", 166);

			arbol->insertar("241011Avel", 122);
			arbol->insertar("241011Barr", 144);
			arbol->insertar("241011Caab", 166);
			//exploto nodo 2
			arbol->insertar("241011Cabb", 122);
			arbol->insertar("241011Bara", 144);
			arbol->insertar("241011Cara", 166);
			//exploto nodo 3
			arbol->insertar("241011Ropa", 122);
			arbol->insertar("241011Sang", 144);
			arbol->insertar("241011Mara", 166);
			arbol->insertar("241011Marx", 166);

			//exploto nodo 1
			arbol->insertar("241011Vota", 122);
			arbol->insertar("241011Wilo", 144);
			arbol->insertar("241011Urug", 166);
			arbol->insertar("241011Vale", 166);

			//exploto nodo 1 otra vez
			arbol->insertar("241011Vali", 144);
			arbol->insertar("241011Valu", 166);
			arbol->insertar("241011Valo", 166);

			IRegistroIndice* busquedaClaveRespuesta;
			string claveRegistroRespuesta;

			//clave existente en una hoja.
			string claveABuscar = "241011Cord";
			busquedaClaveRespuesta = arbol->buscar(claveABuscar);
			claveRegistroRespuesta = ((RegistroArbol*)busquedaClaveRespuesta)->getClave();

			Assert::That(claveABuscar, Is().EqualTo(claveRegistroRespuesta));

			//ultimo registgro del ultimo nodo hoja con clave inexistente.
			bool esNull = false;
			busquedaClaveRespuesta = arbol->buscar("241011Zuzu");
			if (busquedaClaveRespuesta == NULL) esNull = true;

			Assert::That(esNull, Is().EqualTo(true));

			//clave inexistente, devuelve la clave mas proxima.
			busquedaClaveRespuesta = arbol->buscar("241011Maro");
			claveRegistroRespuesta = ((RegistroArbol*)busquedaClaveRespuesta)->getClave();
			string claveMasProxima = "241011Marx";

			Assert::That(claveMasProxima, Is().EqualTo(claveRegistroRespuesta));

			//clave inexistente, devuelve la clave proxima de nodo hoja siguiente.
			busquedaClaveRespuesta = arbol->buscar("241011Sanz");
			claveRegistroRespuesta = ((RegistroArbol*)busquedaClaveRespuesta)->getClave();
			string claveProximaNodoSiguiente = "241011Tasa";

			Assert::That(claveProximaNodoSiguiente, Is().EqualTo(claveRegistroRespuesta));
		}
};
